let comDriver = require('../common/driver');
let BaseBean = require('./BaseBean');

class Core {
    constructor() {
        this.loadjs = require("loadjs");
    }

    async loadUrl(url) {
        return new Promise((resolve, reject) => {
            this.loadjs(url, {
                success: () => {
                    resolve();
                },
                error: err => {
                    reject(err);
                }
            });
        });
    }

    getBeanNamesByTags(...tags) {
        let bean_names = [];
        for (let i = 0; i < tags.length; i++) {
            if (!comDriver.app().tags[tags[i]]) return [];
            bean_names.push(comDriver.app().tags[tags[i]]);
        }
        bean_names = comDriver.array_intersect(...bean_names);
        return bean_names;
    }

    async getBeanClass(name) {
        try {
            if (!name) return null;
            if (!comDriver.app().beans[name]) return null;
            if (comDriver.app().beans[name].beanClass) return comDriver.app().beans[name].beanClass;

            let plug_name = comDriver.app().beans[name].plug;
            if (!comDriver.app().plugs[plug_name]) return null;

            let plug_path_name = comDriver.pathToName(comDriver.app().plugs[plug_name].url);

            if (!comDriver.app.plug_path_names) comDriver.app.plug_path_names = {};
            if (!comDriver.app.plug_path_names[plug_path_name]) {
                comDriver.app.plug_path_names[plug_path_name] = `${comDriver.app().local_base_path}${plug_path_name}/bin/index.js?` + comDriver.randString(20);
            }

            if (!window[plug_path_name]) {
                let plug_path_url = comDriver.app.plug_path_names[plug_path_name];

                await this.loadUrl(plug_path_url);
            }

            if (!window[plug_path_name]) return null;
            if (!window[plug_path_name]['default']) return null;
            let plugClass = await window[plug_path_name]['default']();

            if (!plugClass.beans[name]) return null;
            return plugClass.beans[name].beanClass;
        } catch (e) {
            console.log(e);
            return null;
        }
    }

    async getBeanClassesByTags(...tags) {
        let bean_names = this.getBeanNamesByTags(...tags);
        let results = [];
        for (let i = 0; i < bean_names.length; i++) {
            let result = await this.getBeanClass(bean_names[i]);
            if (result) results.push(result);
        }
        return results;
    }

    async getBean(name) {
        if (!name) return null;
        if (!comDriver.app().beans[name]) return null;

        return comDriver.app().beans[name];
    }

    async getBeanesByTags(...tags) {
        let bean_names = this.getBeanNamesByTags(...tags);

        let results = [];
        for (let i = 0; i < bean_names.length; i++) {
            let result = await this.getBean(bean_names[i]);
            if (result) results.push(result);
        }
        return results;
    }

    async getBeanAndInstance(name, autoCreate = true) {
        if (!name) return null;
        if (!comDriver.app().beans[name]) return null;

        if (!comDriver.app().beans[name].instances) comDriver.app().beans[name].instances = [];

        if (!autoCreate && (comDriver.app().beans[name].instances.length == 0)) return null;

        if ((comDriver.app().beans[name].instances.length == 0) || (comDriver.app().beans[name].mode != 'single')) {
            let type = comDriver.app().beans[name].type;
            let beanClass = await this.getBeanClass(name);
            let instance = null;
            if (type == 'class')
                instance = new beanClass();
            else if (type == 'other')
                instance = beanClass;
            else {
                if (comDriver.protoIsYTClass(beanClass)) {
                    comDriver.app().beans[name].type = 'class';
                    instance = new beanClass();
                } else {
                    comDriver.app().beans[name].type = 'other';
                    instance = beanClass;
                }
            }

            comDriver.app().beans[name].instances.push(instance);
            return {bean: comDriver.app().beans[name], instance: instance, };
        }
        return {bean: comDriver.app().beans[name], instance: comDriver.app().beans[name].instances[0], };
    }

    async getBeanAndInstancesByTags(autoCreate = true, ...tags) {
        let bean_names = this.getBeanNamesByTags(...tags);

        let results = [];
        for (let i = 0; i < bean_names.length; i++) {
            let result = await this.getBeanAndInstance(bean_names[i], autoCreate);
            if (result) results.push(result);
        }
        return results;
    }

    getEventName(event) {
        if (!comDriver.app().event) return event;
        return comDriver.app().event[event] || event;
    }

    async runBean(name, data = {}, failBreak = true, autoCreate = true) {
        let item = await this.getBeanAndInstance(name, autoCreate);
        let params = {
            result: true,
            data: data,
            bean: item ? item.bean : null,
        };
        if (!item) return params;

        if (comDriver.objectIsYTClass(item.instance))
            params = await item.instance.run(params);
        else if (typeof item.instance == 'function')
            params = await item.instance(params);

        return params;
    }

    async runForm(name, data = {}, failBreak = true, autoCreate = true) {
        let item = await this.getBeanAndInstance(name, autoCreate);
        let params = {
            result: true,
            data: data,
            bean: item ? item.bean : null,
        };
        if (!item) return params;
        let form = await item.instance(params);
        new form().run(params);
        return params;
    }

    async runBeansByTags(data = {}, failBreak = true, autoCreate = true, ...tags) {
        let items = await this.getBeanAndInstancesByTags(autoCreate, ...tags);
        let params = {
            result: true,
            data: data,
        };

        for (let i = 0; i < items.length; i++) {
            params.bean = items[i].bean;
            if (comDriver.objectIsYTClass(items[i].instance))
                params = await items[i].instance.run(params);
            else if (typeof items[i].instance == 'function')
                params = await items[i].instance(params);
            else
                break;
        }
        return params;
    }

    getBeanName(name) {
        if (!name) return '';
        if (!comDriver.app().bean_names) return name;
        if (!comDriver.app().bean_names[name]) return name;
        return comDriver.app().bean_names[name];
    }


}


module.exports = Core;
